% \iffalse meta-comment
%
%% File: latex-lab-float.dtx (C) Copyright 2023 LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
%
% The development version of the bundle can be found below
%
%    https://github.com/latex3/latex2e/required/latex-lab
%
% for those people who are interested or want to report an issue.
%
\def\ltlabfloatdate{2023-07-20}
\def\ltlabfloatversion{0.81a}
%<*driver>
\documentclass{l3doc}
\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-float.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \title{The \textsf{latex-lab-floats} package\\
% Tagging of floats }
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabfloatversion\ \ltlabfloatdate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
% \providecommand\hook[1]{\texttt{#1}}
% \begin{documentation}
% \begin{abstract}
% The following code implements a first draft for the tagging of float 
% environments
% \end{abstract}
% 
% 
% \section{Introduction}
% 
% The code here handle the tagging of float environments. 
% 
% Figures (and tables) are in \LaTeX{} typically typeset in float environments. 
% These are boxes which can \emph{float} away to special float areas on the pages, 
% e.g., to the top or the bottom of a page or to special float pages.
% If the rules allow it they can also be placed in the main text stream (\enquote{here}).  
% Floats can also be collected at the end of the document. 
% In either case  the order within each type of floats 
% (e.g., figures, tables, algorithms, etc.) is preserved.
% 
% A special type, called a H-float, (provided by the float package)
% is always placed in the main text stream and does not
% necessarly preserve the order with normal floats of the same type: It is basically
% a minipage with a caption.
% 
% Floats typically contain a figure (or a table, etc.) and a caption, 
% but more complex constructions with subfigures,
% copyright statements, sources or additional description are possible too.
% 
% In the \LaTeX{} source a float is normally more or less at the place of 
% the first call-out, but when preparing a document for print the code 
% is sometimes moved to place floats in a more visually pleasing way.
% 
% \section{Tagging}
% 
% Floats (with the exception of H-floats) do not belong into the text stream, they
% are \enquote{consultation objects}: Readers must be able to choose if and when they read the float.
% Floats have captions, the PDF rules require that a \texttt{Caption} is the first or last
% structure in its parent structure. 
% This poses some challenges on a good tagging.
% 
% In PDF~2.0 there is the suitable \texttt{Aside} tag which hopefully will 
% be handled correctly regarding the reading order once processor actually support
% PDF~2.0. But in PDF~1.7 we rolemap it to \texttt{Note} and this doesn't lead to 
% a good reading order. The code therefore collect the float structures and moves
% them to a \texttt{Sect} the end of the document or the chapter 
% (H-floats once they are handled will not be moved).
% 
% To fulfill the requirement that a \texttt{Caption} should be at the begin or end, we always
% move it to the begin of the structure. If a float has two captions the author
% has to insert a command which splits the float in two.
% 
% Subfigures and subcaptions are currently not handled, but will be implemented
% as simple \texttt{Part} with their own \texttt{Caption}.    
% 
% \section{Links}
% The code disable the caption patches from hyperref. It will add an anchor at the
% begin of the float or a split. It changes caption so that a link to a caption label
% will go to the begin of the float.
% 
% \section{Tools}
% 
% The code add two keys for the \cs{tagtool} command
% 
% \begin{description}
% \item[flush-floats]  This will flush out the collected floats sofar (currently
% table and figure. The value is a sectioning level, e.g. \texttt{section} or \texttt{chapter},
% the floats will then inserted as a \texttt{Sect} of this level (all \texttt{Sect} of smaller or equal
% level are closed). The key then starts a new container for following floats.
% If no value is given, the \texttt{Sect} is at the document level. The code automatically
% flush all open floats at the end of the document.
% 
% \item[split-float] This can be used inside a float if there are two captions.
% It will only work reasonably well if the content of the float parts are in a sensible order
% and can be separated by this command. More complex setups with tabulars will need more
% thoughts
% 
%  \end{description} 
%                                    
%  
%    \begin{macrocode}
%<@@=tag>
%<*package>
%    \end{macrocode}
% \end{documentation}
% \begin{implementation}
% \section{Implementation} 
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-float} {\ltlabfloatdate} {\ltlabfloatversion}
  {Code related to the tagging of floats}
%    \end{macrocode}
% \subsection{Variables}
% We rolemap to float to Aside, and float sections to Sect.
%
% \begin{variable}{
%  \g_@@_float_sect_prop,
%  \g_@@_float_types_seq,
%  \@current@float@struct
%   }
% These variables will hold the structure number for the float container  
% and the list of float types. Currently only figure and table are supported
% TODO: interface to declare new float types.
%    \begin{macrocode}
\prop_new:N \g_@@_float_sect_prop
\seq_new:N  \g_@@_float_types_seq
\seq_gput_right:Nn \g_@@_float_types_seq {figure}
\seq_gput_right:Nn \g_@@_float_types_seq {table}
\tl_new:N\@current@float@struct
%    \end{macrocode}
% \end{variable}
% 
% \begin{variable}{\g_@@_float_sect_bool}
% With this boolean float collection is switched on and off.
% Currently it is always on and set globally. 
% TODO: think if an interface is needed.
% TODO: would a local variable make more sense?
%    \begin{macrocode}
\bool_new:N       \g_@@_float_sect_bool
\bool_gset_true:N  \g_@@_float_sect_bool
%    \end{macrocode}
% \end{variable}
% 
% 
%\subsection{Moving float structures}
% 
% Currently it is for all float types or none.
% Probably we will need some more options here to select some float types.
% 
% \begin{macro}{\@@_float_init_collect:}
% This initializes a container structure for every float type.
% It can be used more than once in a document, this allows to have e.g.
% chapter wise containers.
%    \begin{macrocode}
\cs_new_protected:Npn\@@_float_init_collect:
  { 
    \bool_if:NT\g_@@_float_sect_bool
      {
        \seq_map_inline:Nn\g_@@_float_types_seq
          {
            \tag_struct_begin:n{tag=##1s,stash}
            \prop_gput:Nnx\g_@@_float_sect_prop {##1-struct}{\int_use:N\c@g__tag_struct_abs_int} 
            \tag_struct_end:
          }  
      }   
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_float_stop_sect:}
% This pushes out the floats. For every type is checks if there is actually
% a float of this type and then writes out the container structure.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_stop_sect:
  {
    \bool_if:NT\g_@@_float_sect_bool
     {
      \seq_map_inline:Nn\g_@@_float_types_seq
        {
          \prop_get:NnNT\g_@@_float_sect_prop{##1-used}\l_@@_tmpa_tl
            {
              \exp_args:Ne
              \tag_struct_use_num:n{\prop_item:Nn\g_@@_float_sect_prop{##1-struct}}
              \prop_gremove:Nn \g_@@_float_sect_prop{##1-used}
            }  
        }  
     }   
  } 
%    \end{macrocode}
% \end{macro}

% \begin{macro}{flush-floats}
% This is a key for \cs{tagtool} to flush out the collected floats. 
% The value allows to set to which level the create Sect contains. 
% So \texttt{section} will close all previous Sect until the section level
% and create a new section.
%    \begin{macrocode}
\keys_define:nn { tag / tool} 
 {
   flush-floats .code:n = 
     {
       \keys_set:nn {tag / tool} {sec-stop=#1}
       \@@_float_stop_sect:
       \@@_float_init_collect:
     },
   flush-float .default:n = Document  
 }
%    \end{macrocode}
% \end{macro}
% We need at least one pair
%    \begin{macrocode}
\AddToHook{begindocument/end}[latex-lab/float]
  {\@@_float_init_collect:}
\AddToHook{tagpdf/finish/before}[latex-lab/float]
  {\par\__tag_sec_end:n{-10}\@@_float_stop_sect:}
\DeclareHookRule{tagpdf/finish/before}{latex-lab/float}{before}{tagpdf}
%    \end{macrocode}
% \subsection{Splitting floats}
% \begin{macro}{split-float}
% TODO: check if the target affect spacing!! 
%    \begin{macrocode}
\keys_define:nn { tag / tool}
  {
   split-float .code:n = 
    { 
      \@@_float_end:
      \@@_float_begin:
      \MakeLinkTarget[tagstructure]{g__tag_struct_abs_int}
    }  
 }
%    \end{macrocode}
% \end{macro}
 
% \subsection{Patching}
% \begin{macro}{\@@_float_stop_par:,\@@_float_start_par:}
% if a float is in a par, we need commands to stop and restart the P-mc
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_stop_par:
  {
    \tag_mc_end:
    \bool_if:NF \g_@@_float_sect_bool
     { 
      \tag_struct_end:
     }  
  }
\cs_new_protected:Npn \@@_float_start_par:
  {
    \bool_if:NF \g_@@_float_sect_bool
     { 
      \tag_struct_begin:n{tag=text}%
     }
   \tag_mc_begin:n{tag=P}    
  }
 
%    \end{macrocode}
% \end{macro}
% These commands are the main commands to start and end the float tagging.
% 
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_begin:
 {%
%    \end{macrocode}
% We test if the float structure should be included directly or move to a dedicated section.
%    \begin{macrocode}
  \bool_if:NTF\g_@@_float_sect_bool
   {
     \exp_args:Ne
     \tag_struct_begin:n{tag=float,parent=0\prop_item:No\g_@@_float_sect_prop{\@captype-struct}}%
     \prop_gput:Nxx \g_@@_float_sect_prop {\@captype-used}{true}
   }
   {
     \tag_struct_begin:n{tag=float}
   }
     \tl_set:Nx\@current@float@struct{\tag_get:n{struct_num}}%
     \typeout{Float structure: \@current@float@struct}   
 }

\cs_new_protected:Npn\@@_float_end:{\tag_struct_end:} %end Aside

%    \end{macrocode}
% This patches the main command \cs{@xfloat}.
% There is a : in the code, so we disable expl3 syntax
%    \begin{macrocode}
\ExplSyntaxOff
\def\@xfloat #1[#2]{%
  \@nodocument
  \def \@captype {#1}%
   \def \@fps {#2}%
   \@onelevel@sanitize \@fps
   \def \reserved@b {!}%
   \ifx \reserved@b \@fps
     \@fpsadddefault
   \else
     \ifx \@fps \@empty
       \@fpsadddefault
     \fi
   \fi
   \ifhmode
     \@bsphack
%    \end{macrocode}
% If the float is in hmode we have to interrupt the P 
%    \begin{macrocode}
     \@nameuse{@@_float_stoppar:} %<---end P     
     \@floatpenalty -\@Mii
   \else
     \@floatpenalty-\@Miii
   \fi
  \ifinner
     \@parmoderr\@floatpenalty\z@
  \else
    \@next\@currbox\@freelist
      {%
       \@tempcnta \sixt@@@@n
       \expandafter \@tfor \expandafter \reserved@a
         \expandafter :\expandafter =\@fps
         \do
          {%
           \if \reserved@a h%
             \ifodd \@tempcnta
             \else
               \advance \@tempcnta \@ne
             \fi
           \else\if \reserved@a t%
             \@setfpsbit \tw@
           \else\if \reserved@a b%
             \@setfpsbit 4%
           \else\if \reserved@a p%
             \@setfpsbit 8%
           \else\if \reserved@a !%
             \ifnum \@tempcnta>15
               \advance\@tempcnta -\sixt@@@@n\relax
             \fi
           \else
             \@latex@error{Unknown float option `\reserved@a'}%
             {Option `\reserved@a' ignored and `p' used.}%
             \@setfpsbit 8%
           \fi\fi\fi\fi\fi
           }%
       \@tempcntb \csname ftype@\@captype \endcsname
       \multiply \@tempcntb \@xxxii
       \advance \@tempcnta \@tempcntb
       \global \count\@currbox \@tempcnta
       }%
    \@fltovf
  \fi
%    \end{macrocode}
% This starts the structure for the float.
%    \begin{macrocode}
  \@nameuse{@@_float_begin:}%
  \global \setbox\@currbox
    \color@vbox
      \normalcolor
      \vbox \bgroup
        \hsize\columnwidth
        \@parboxrestore
        \@floatboxreset
%    \end{macrocode}
% We add a target for links. TODO: check that it doesn't affect spacing!!
%    \begin{macrocode}
        \MakeLinkTarget[tagstructure]{g__tag_struct_abs_int}%
}%
%    \end{macrocode}
%  The end code of the float ...
%    \begin{macrocode}
\def\end@float{%
  \@endfloatbox
  \@nameuse{@@_float_end:}%
  \ifnum\@floatpenalty <\z@
    \@largefloatcheck
    \@cons\@currlist\@currbox
    \ifnum\@floatpenalty <-\@Mii
      \penalty -\@Miv
      \@tempdima\prevdepth
      \vbox{}%
      \prevdepth\@tempdima
      \penalty\@floatpenalty
    \else
      \vadjust{\penalty -\@Miv \vbox{}\penalty\@floatpenalty}\@Esphack
      \@nameuse{@@_float_start_par:} %restart P safe here??
    \fi
  \fi
}
%    \end{macrocode}
%  and similar for double floats:
%    \begin{macrocode}
\def\end@dblfloat{%
  \if@twocolumn
    \@endfloatbox
    \@nameuse{@@_float_end:}%
    \ifnum\@floatpenalty <\z@
      \@largefloatcheck
      \global\dp\@currbox1sp %
      \@cons\@currlist\@currbox
      \ifnum\@floatpenalty <-\@Mii
        \penalty -\@Miv
        \@tempdima\prevdepth
        \vbox{}%
        \prevdepth\@tempdima
        \penalty\@floatpenalty
      \else
        \vadjust{\penalty -\@Miv \vbox{}\penalty\@floatpenalty}\@Esphack
        \@nameuse{@@_float_start_par:} %restart P safe here??
      \fi
    \fi
  \else
    \end@float
  \fi
}%
\ExplSyntaxOn
%    \end{macrocode}
%
% \subsection{Handling captions}
% 
% To avoid that hyperref interferes we disable its patches:
%    \begin{macrocode}
\def\hyper@nopatch@caption{}
%    \end{macrocode}
%
% With hyperref that means that the \cs{refstepcounter} now can affect spacing so we
% change that to the kernel refstepcounter:
%    \begin{macrocode}
\let\@kernel@refstepcounter\refstepcounter %as long it is not in the kernel
\def\caption{%
   \ifx\@captype\@undefined
     \@latex@error{\noexpand\caption outside float}\@ehd
     \expandafter\@gobble
   \else
     \@kernel@refstepcounter\@captype
     \expandafter\@firstofone
   \fi
   {\@dblarg{\@caption\@captype}}%
}
%    \end{macrocode}
% As we will use the structure number in the target, we need to provide a
% theH-representation. (Once the kernel will create
% theH-representation generally this will be provided automatically, as tagpdf uses
% \cs{newcounter})
%    \begin{macrocode}
\providecommand\theHg__tag_struct_abs_int{\int_use:N\c@g__tag_struct_abs_int}
%    \end{macrocode}

% \begin{macro}{\@makecaption}
% \cs{@makecaption} is defined by the classes so we overwrite it for now
% at begin document.
%    \begin{macrocode}
\AddToHook{begindocument}
  {
    \long\def\@makecaption#1#2{%
      \vskip\abovecaptionskip
      \xdef\@currentHref{tagstructure.\@current@float@struct}%
%    \end{macrocode}
% we don't want tagging when storing the caption for the singleline check
%    \begin{macrocode}
      \tag_stop:n{caption}
      \sbox\@tempboxa{#1:~#2}%
      \tag_start:n{caption} 
%    \end{macrocode}
% we stop paratagging. TODO: check 
%    \begin{macrocode}
      \tagtool{para=false}
      \tag_struct_begin:n{tag=Caption,parent=\@current@float@struct}
%    \end{macrocode}
% move the caption to the begin of the float structure:
%    \begin{macrocode}
     \seq_gpop_right:cN {g__tag_struct_kids_\@current@float@struct _seq}\l_@@_tmpa_tl
     \seq_gput_left:cV  {g__tag_struct_kids_\@current@float@struct _seq}\l_@@_tmpa_tl  
      \ifdim \wd\@tempboxa >\hsize
        \tag_struct_begin:n{tag=Lbl}
        \tag_mc_begin:n{}
          #1:~ 
        \tag_mc_end:
        \tag_struct_end:
        \tag_mc_begin:n{}  
          #2\par
        \tag_mc_end:  
      \else
%    \end{macrocode}
% we don't reuse the box as it doesn't contain tagging, but set the text explicitly.
%    \begin{macrocode}
          \global \@minipagefalse
        \hb@xt@\hsize{\hfil
         \tag_struct_begin:n{tag=Lbl}
          \tag_mc_begin:n{}
           #1:~ 
          \tag_mc_end:
         \tag_struct_end:
         \tag_mc_begin:n{}  
          #2
         \tag_mc_end:\hfil}%
       \fi
       \tag_struct_end: %caption
      \vskip\belowcaptionskip}
  }  
%    \end{macrocode}
% \end{macro}
%   
%    \begin{macrocode}
%</package>  
%    \end{macrocode}

%    \begin{macrocode}
%<*latex-lab>
\ProvidesFile{float-latex-lab-testphase.ltx}
        [\ltlabfloatdate\space v\ltlabfloatversion\space latex-lab wrapper float]
\RequirePackage{latex-lab-testphase-float}
%</latex-lab>
%    \end{macrocode}
% \end{implementation}
